`ifndef AHBL2APB_TB_SV
`define AHBL2APB_TB_SV

`timescale 1ns/1ps

`include "uvm_macros.svh"
import uvm_pkg::*;
import apb_pkg::*;

module ahbl2apb_tb();

	parameter HCLK_PERIOD 		= 10;
	parameter HCLK_PCLK_RAITO = 2;

	logic 			clk;
	logic 			rstn;
	logic 			apbactive;

	logic[3:0] 	cnt;
	logic      	pclken;
	logic      	pclk;

	apb_interface 			apb_if(pclk, rstn);
	ahbl_interface 			ahbl_if(clk, rstn);
	ahbl2apb_interface 	ahbl2apb_if();

	// clk gen
	initial begin : clk_gen
		clk <= 1'b1;

		forever begin
			#(HCLK_PERIOD / 2);
			clk <= ~clk;
		end
	end


	// counter for pclken
	always @(posedge clk or negedge rstn) begin
		if(!rstn)
			cnt <= 'd0;
		else if(cnt == (HCLK_PCLK_RAITO - 1'b1))
			cnt <= 'd0;
		else
			cnt <= cnt + 1'b1;
	end

	// pclken gen
	always @(negedge clk or negedge rstn) begin
		if(!rstn)
			pclken <= 1'b0;
		else if(cnt == (HCLK_PCLK_RAITO - 1'b1))
			pclken <= 1'b1;
		else
			pclken <= 1'b0;
	end

	assign pclk 						= pclken & clk;

	assign ahbl2apb_if.clk 	= clk;
	assign rstn							= ahbl2apb_if.rstn;

	cmsdk_ahb_to_apb #(
		.ADDRWIDTH 			(16),
		.REGISTER_RDATA (1),
		.REGISTER_WDATA (0)
	) DUT (
		.HCLK 			(clk									),
		.HRESETn 		(rstn									),
		.PCLKEN 		(pclken								),

		.HSEL 			(ahbl_if.HSEL					),
		.HADDR 			(ahbl_if.HADDR[15:0]	),
		.HTRANS 		(ahbl_if.HTRANS				),
		.HSIZE 			(ahbl_if.HSIZE				),
		.HPROT 			(ahbl_if.HPROT				),
		.HWRITE 		(ahbl_if.HWRITE				),
		.HREADY 		(ahbl_if.HREADYOUT		),
		.HWDATA 		(ahbl_if.HWDATA[31:0]	),

		.HREADYOUT 	(ahbl_if.HREADYOUT		),
		.HRDATA 		(ahbl_if.HRDATA[31:0]	),
		.HRESP 			(ahbl_if.HRESP				),
		
		.PADDR 			(apb_if.PADDR[15:0]		),
		.PSEL 			(apb_if.PSEL					),
		.PENABLE 		(apb_if.PENABLE				),
		.PWRITE 		(apb_if.PWRITE				),
		.PWDATA			(apb_if.PWDATA				),

		.PRDATA 		(apb_if.PRDATA				),
		.PREADY 		(apb_if.PREADY				),
		.PSLVERR 		(apb_if.PSLVERR				),
		
		.PSTRB			(apb_if.PSTRB					),
		.PPROT			(apb_if.PPROT					),
		.APBACTIVE 	(apbactive						)
	);


	initial begin
		uvm_config_db #(virtual ahbl_interface)::set(null, "uvm_test_top.env.ahbl_mst_agt", "vif", ahbl_if);
		uvm_config_db #(virtual apb_interface)::set(null, "uvm_test_top.env.apb_slv_agt", "vif", apb_if);
	end

	initial begin
		run_test();
	end

//	initial begin
//		$fsdbDumpfile("ahbl2apb_tb.fsdb");
//		$fsdbDumpvars(0);
//	end

	property p_psel_high_then_apbactive_high;
		@(posedge pclk) disable iff(!rstn)
		apb_if.PSEL |-> apbactive;
	endproperty

	property p_apbactive_high_then_psel_high;
		@(posedge pclk) disable iff(!rstn)
		$rose(apbactive) |-> apb_if.PSEL;
	endproperty

	property p_hresp_hreadyout;
		@(posedge clk) disable iff(!rstn)
		ahbl_if.HRESP |-> ahbl_if.HREADYOUT && !$past(ahbl_if.HREADYOUT);
	endproperty

	a_psel_high_then_apbactive_high : assert property(p_psel_high_then_apbactive_high);
	a_apbactive_high_then_psel_high : assert property(p_apbactive_high_then_psel_high);
	a_hresp_hreadyout								: assert property(p_hresp_hreadyout);

endmodule : ahbl2apb_tb


`endif // AHBL2APB_TB_SV
